package db

import (
	"errors"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"gitee.com/sillyman/PingHostsWebView/models"
)

var (
	// dbConn 数据库连接
	dbConn      *gorm.DB
	dbConnMutex sync.Mutex

	// dataDir 数据库目录
	dataDir = "./data"

	newLogger = logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold: 2 * time.Second, // 慢 SQL 阈值
			LogLevel:      logger.Warn,     // Log level
			Colorful:      false,           // 禁用彩色打印
		},
	)
)

// MustObtainMainDB
func MustObtainMainDB() *gorm.DB {
	dbConnMutex.Lock()

	if dbConn != nil {
		return dbConn
	}

	var err error
	// 需要使用Sqlite3.7.0以上的版本，此版本引入了WAL日志模式，此日志模式读写可以充分并发，一次写事务只需要一次磁盘同步。
	// 建议不开启共享缓存，虽然共享内存模式能减少内存的使用，但是以牺牲并发性能为代价的。
	dbConn, err = gorm.Open(sqlite.Open(filepath.Join(dataDir, "main.db3?_journal_mode=MEMORY&_synchronous=NORMAL")), &gorm.Config{
		Logger: newLogger,
	})

	if err != nil {
		panic(err)
	}

	if err := dbConn.AutoMigrate(&models.PingSummary{}, &models.HostConfig{}); err != nil {
		panic(err)
	}
	return dbConn
}

func ReleaseMainDB() {
	dbConnMutex.Unlock()
}

// MustOpenPingRecordDB
func MustOpenPingRecordDB(ip net.IP) *gorm.DB {
	db, err := gorm.Open(sqlite.Open(filepath.Join(dataDir, getPingRecordDBFilename(ip))+"?cache=shared&_journal_mode=MEMORY&_synchronous=NORMAL"), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		panic(err)
	}

	if err := db.AutoMigrate(&models.PingRecord{}); err != nil {
		panic(err)
	}

	return db
}

// MustDelPingRecordDB 删除Ping记录的数据文件，删除前需要先关闭db连接
func MustDelPingRecordDB(ip net.IP) {
	if err := os.Remove(filepath.Join(dataDir, getPingRecordDBFilename(ip))); err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return
		}
		panic(err)
	}
}

func getPingRecordDBFilename(ip net.IP) string {
	return strings.ReplaceAll(strings.ReplaceAll(ip.String(), ".", "_"), ":", "_") + ".db3"
}
